//
//  HomeTableViewController.swift
//  我的微博
//
//  Created by H on 15/7/28.
//  Copyright © 2015年 H. All rights reserved.
//

import UIKit

import UIKit

class HomeTableViewController: BaseTableViewController {
    
    /// 微博数据数组
    var statuses: [Status]? {
        didSet {
            // 刷新数据
            tableView.reloadData()
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 如果用户没有登录，设置访客视图，返回
        if !UserAccount.userLogon {
            visitorView?.setupViewInfo(true, imagename: "visitordiscover_feed_image_smallicon", message: "关注一些人，回这里看看有什么惊喜")
            
            return
        }
        
        prepareTableView()
        loadData()
    }
    
    /// 准备表格视图
    private func prepareTableView() {
        // 注册原型 cell
        // rawValue 返回枚举对应实际数值
        tableView.registerClass(StatusNormalCell.self, forCellReuseIdentifier: StatusCellIdentifier.NormalCell.rawValue)
        tableView.registerClass(StatusForwardCell.self, forCellReuseIdentifier: StatusCellIdentifier.ForwardCell.rawValue)
        
        // 设置表格的预估行高(方便表格提前计算预估行高，提高性能) - 尽量准确，能够提高性能
        // 能够减少调用行高的次数
        tableView.estimatedRowHeight = 300
        // 取消分割线
        tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        
        // 刷新控件，高度是 60
        refreshControl = HMRefreshControl()
        // 添加监听方法
        refreshControl?.addTarget(self, action: "loadData", forControlEvents: UIControlEvents.ValueChanged)
    }
    
    /// 上拉刷新的标记
    private var pullupRefreshFlag = false
    /// 加载数据
    func loadData() {
        // 开始动画 - 只是开启了刷新控件的动画，并不会触发加载数据的方法
        refreshControl?.beginRefreshing()
        
        // 刷新新数据，获取到数组中第一条记录的 id
        // 第一次执行此方法的时候，statuses为空since_id = 0，加载最新的20条记录
        var since_id = statuses?.first?.id ?? 0
        
        // 判断是否是上拉刷新
        var max_id = 0
        if pullupRefreshFlag {
            since_id = 0
            // 记录数组最后一条记录的 id
            max_id = statuses?.last?.id ?? 0
        }
        
        Status.loadStatus(since_id, max_id: max_id) { (dataList, error) -> () in
            // 关闭刷新控件，结束刷新动画
            self.refreshControl?.endRefreshing()
            
            if error != nil {
                print(error)
                return
            }
            
            let count = dataList?.count ?? 0
            print("刷新到 \(count) 条数据")
            // 只有下拉刷新才需要提示
            if since_id > 0 {
                self.showPulldownTip(count)
            }
            
            // 如果没有数据，直接返回
            if count == 0 {
                return
            }
            
            if since_id > 0 {       // 做下拉刷新，应该将结果集合放在之前数组的前面
                self.statuses = dataList! + self.statuses!
            } else if max_id > 0 {  // 做上拉刷新，应该讲结果集合放在数组的后面
                self.statuses! += dataList!
                
                // 复位上拉刷新标记，保证下一次仍然能够上拉
                self.pullupRefreshFlag = true
            } else {
                self.statuses = dataList
            }
        }
    }
    
    /// 显示下拉刷新的数据条数
    private func showPulldownTip(count: Int) {
        // 定义标签
        let h: CGFloat = 44
        let label = UILabel(frame: CGRect(x: 0, y: -2 * h, width: view.bounds.width, height: h))
        label.backgroundColor = UIColor.orangeColor()
        label.textColor = UIColor.whiteColor()
        label.textAlignment = NSTextAlignment.Center
        label.text = "刷新到 \(count) 条微博"
        
        // 将 label 添加到界面(view不合适，会一起滚动)
        // 加载 navBar 上面，不会随着 tableView 一起滚动
        navigationController?.navigationBar.insertSubview(label, atIndex: 0)
        
        UIView.animateWithDuration(2.0, animations: { () -> Void in
            // 自动反转动画
            UIView.setAnimationRepeatAutoreverses(true)
            // 移动 label 的位置
            label.frame = CGRectOffset(label.frame, 0, 3 * h)
            }) { (_) -> Void in
                label.removeFromSuperview()
        }
    }
    
    // MARK: - 数据源方法
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("计算行数")
        return statuses?.count ?? 0
    }
    
    // 每次要显示 cell 的时候，会调用此方法，根据 indexPath 判断数据方法
    // 如果 indexPath == 微博数组的总数 - 1，表示要显示最后一行了
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        // 根据微博类型，选取不同的 ID
        let status = statuses![indexPath.row]
        
        let cell = tableView.dequeueReusableCellWithIdentifier(StatusCellIdentifier.cellId(status), forIndexPath: indexPath) as! StatusCell
        
        // 判断 indexPath 的数值
        if indexPath.row == statuses!.count - 1 {
            // 设置上拉刷新标记
            pullupRefreshFlag = true
            // 刷新数据
            loadData()
        }
        
        cell.status = statuses![indexPath.row]
        
        return cell
    }
    
    /// 返回行高 － 如果是固定值，可以直接通过属性设置，效率更高
    /**
    行高缓存
    1. NSCache - 内存缓存，iOS 8.0 模拟器有 bug，不能 removeAll，一旦 removeAll 之后，再也没法使用了
    真机没有问题，在实际开发中，一定以真机测试为准！
    SDWebImage 存在什么问题
    1> 加载 GIF 的时候，内存会狂飙！
    2. 自定义行高`缓存字典`
    3. 直接利用微博的`模型` - 行高数据只是一个小数，并不会有太大的内存消耗！
    不需要在控制器中，额外定义属性！
    
    提示：如果表格高度是固定的，一定不要通过代理返回行高！可以直接设置属性！
    
    表格 & 数据源执行的顺序
    有预估行高
    1> 行数，知道多少行，根据预估行高，计算整个 tableView 的预估 contentSize，保证能够滚动
    
    2> 数据源 cell，获取要显示的 cell，会直接调用行高方法，返回当前行的高度
    3> 行高
    
    2.3会重复调用，一直到超出当前屏幕位置
    contentSize 会有一个变化，显示的行会用计算好的行高，没有显示的行，仍然用预估行高
    如果都滚动完成，contentSize 才是一个准确的值
    
    好处，提前计算的数据量小
    缺点，滚动过程中，临时计算行高，如果行高计算过于复杂，会影响性能！
    
    没有预估行高
    1> 行数，知道有多少行
    2> 行高，计算每一行的行高，累加，就能够得到 contentSize 的 height
    3> 数据源 cell，当 cell 显示的时候，整个 tableView 的 contentSize 已经计算完毕，能够保证快速滚动！
    
    重点：UITableView 是继承自 UIScrollView，滚动依赖于 `contentSize`
    
    tableView.cellForRowAtIndexPath(indexPath) 通常是在表格的其他代理方法，例如：选中行中根据索引获取 cell
    注意：调用的时候，cell一定已经被创建出来！
    
    */
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        
        // 判断模型中，是否已经缓存了行高
        // 1. 获取模型
        let status = statuses![indexPath.row]
        
        if let h = status.rowHeight {
            return h
        }
        
        // 其他位置获取 cell 的方法，但是本函数中，无法使用此方法获取到 cell
        //        let c = tableView.cellForRowAtIndexPath(indexPath)
        print("计算行高 \(indexPath)")
        
        // 2. 获取 cell - dequeueReusableCellWithIdentifier 带 indexPath 的函数会调用计算行高的方法
        // 会造成死循环，在不同版本的 Xcode 中 行高的计算次数不一样！尽量要优化！
        // 如果不做处理，会非常消耗性能！
        let cell = tableView.dequeueReusableCellWithIdentifier(StatusCellIdentifier.cellId(status)) as? StatusCell
        
        // 3. 记录并返回计算的行高
        status.rowHeight = cell!.rowHeight(status)
        
        return status.rowHeight!
    }
}
